﻿namespace Pub.Class
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Drawing;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Threading;
    using System.Xml;
    using System.Xml.Linq;
    using System.Xml.Serialization;

    public static class ClassExtensions
    {
        public static T Clone<T>(this T o) where T: class
        {
            MethodInfo[] methods = o.GetType().BaseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            MethodInfo info = null;
            foreach (MethodInfo info2 in methods)
            {
                if (info2.Name == "MemberwiseClone")
                {
                    info = info2;
                    break;
                }
            }
            if (info.IsNotNull())
            {
                return (T) info.Invoke(o, null);
            }
            return default(T);
        }

        public static IEnumerable<TSource> Concat<TSource>(this TSource first, IEnumerator<TSource> right)
        {
            yield return first;
            while (true)
            {
                if (!right.MoveNext())
                {
                    yield break;
                }
                yield return right.Current;
            }
        }

        public static T DebugDump<T>(this T value, string name)
        {
            if (name.IsNullEmpty())
            {
                throw new ArgumentNullException("name");
            }
            using (DebugWriter writer = new DebugWriter())
            {
                return value.Dump<T>(name, writer);
            }
        }

        public static string Dump<T>(this T value, string name)
        {
            using (StringWriter writer = new StringWriter(CultureInfo.InvariantCulture))
            {
                value.Dump<T>(name, writer);
                return writer.ToString();
            }
        }

        public static T Dump<T>(this T value, string name, TextWriter writer)
        {
            if (name.IsNullEmpty())
            {
                throw new ArgumentNullException("name");
            }
            if (writer.IsNull())
            {
                throw new ArgumentNullException("writer");
            }
            Dumper.Dump(value, name, writer);
            return value;
        }

        public static IEnumerable<T> GetDescendants<T>(this T root, Func<T, IEnumerable<T>> childSelector, Predicate<T> filter)
        {
            foreach (T iteratorVariable0 in childSelector(root))
            {
                if (filter.IsNull() || filter(iteratorVariable0))
                {
                    yield return iteratorVariable0;
                }
                IEnumerator<T> enumerator = iteratorVariable0.GetDescendants<T>(childSelector, filter).GetEnumerator();
                while (enumerator.MoveNext())
                {
                    T current = enumerator.Current;
                    yield return current;
                }
            }
        }

        public static IEnumerable<T> GetDescendants<TRoot, T>(this TRoot root, Func<TRoot, IEnumerable<T>> rootChildSelector, Func<T, IEnumerable<T>> childSelector, Predicate<T> filter)
        {
            foreach (T iteratorVariable0 in rootChildSelector(root))
            {
                if (filter.IsNull() || filter(iteratorVariable0))
                {
                    yield return iteratorVariable0;
                }
                IEnumerator<T> enumerator = iteratorVariable0.GetDescendants<T>(childSelector, filter).GetEnumerator();
                while (enumerator.MoveNext())
                {
                    T current = enumerator.Current;
                    yield return current;
                }
            }
        }

        public static void If<T>(this T t, Predicate<T> predicate, Action<T> action) where T: class
        {
            if (predicate(t))
            {
                action(t);
            }
        }

        public static T If<T>(this T t, Predicate<T> predicate, Func<T, T> func) where T: struct
        {
            if (!predicate(t))
            {
                return t;
            }
            return func(t);
        }

        public static void If<T>(this T t, Predicate<T> predicate, Action<T> action1, Action<T> action2) where T: class
        {
            if (predicate(t))
            {
                action1(t);
            }
            else
            {
                action2(t);
            }
        }

        public static T If<T>(this T t, Predicate<T> predicate, Func<T, T> func1, Func<T, T> func2) where T: struct
        {
            if (!predicate(t))
            {
                return func2(t);
            }
            return func1(t);
        }

        public static T IfNull<T>(this T obj, Func<T> func) where T: class
        {
            if (!obj.IsNull() && !obj.IsDBNull())
            {
                return obj;
            }
            if (!func.IsNull())
            {
                return func();
            }
            return default(T);
        }

        public static object IfNull(this object obj, object defaultValue)
        {
            if (!obj.IsNull() && !obj.IsDBNull())
            {
                return obj;
            }
            return defaultValue;
        }

        public static T IfNull<T>(this T obj, T defaultValue)
        {
            if (!obj.IsNull() && !obj.IsDBNull())
            {
                return obj;
            }
            return defaultValue;
        }

        public static bool In<T>(this T t, IEnumerable<T> c)
        {
            return c.Any<T>(i => i.Equals(t));
        }

        public static bool In<T>(this T obj, params T[] values)
        {
            return (Array.IndexOf<T>(values, obj) != -1);
        }

        public static bool IsBetween<T>(this T value, T minValue, T maxValue) where T: IComparable<T>
        {
            return value.IsBetween<T>(minValue, maxValue, null);
        }

        public static bool IsBetween<T>(this T value, T minValue, T maxValue, IComparer<T> comparer) where T: IComparable<T>
        {
            comparer = comparer ?? Comparer<T>.Default;
            int num = comparer.Compare(minValue, maxValue);
            if (num < 0)
            {
                return ((comparer.Compare(value, minValue) >= 0) && (comparer.Compare(value, maxValue) <= 0));
            }
            if (num == 0)
            {
                return (comparer.Compare(value, minValue) == 0);
            }
            return ((comparer.Compare(value, maxValue) >= 0) && (comparer.Compare(value, minValue) <= 0));
        }

        public static bool IsDefault<T>(this T value)
        {
            return object.Equals(value, default(T));
        }

        public static T Pipe<T>(this T o, Action<T> action)
        {
            T local = o;
            action(local);
            return local;
        }

        public static R Pipe<T, R>(this T o, Func<T, R> action)
        {
            T arg = o;
            return action(arg);
        }

        public static TResult Select<TSource, TResult>(this TSource entity, Func<TSource, TResult> selector)
        {
            return selector(entity);
        }

        public static byte[] ToBinary<T>(this T o) where T: class
        {
            if ((o.GetType().Attributes & TypeAttributes.Serializable) == TypeAttributes.AnsiClass)
            {
                throw new Exception("需要[Serializable] attribute");
            }
            BinaryFormatter formatter = new BinaryFormatter();
            using (MemoryStream stream = new MemoryStream())
            {
                formatter.Serialize(stream, o);
                return stream.ToArray();
            }
        }

        public static byte[] ToBinaryDeflateCompress<T>(this T o) where T: class
        {
            return o.ToBinary<T>().DeflateCompress();
        }

        public static string ToHex(this Color c)
        {
            return (string.Format("{0:X2}", Convert.ToInt32(c.R)) + string.Format("{0:X2}", Convert.ToInt32(c.G)) + string.Format("{0:X2}", Convert.ToInt32(c.B)));
        }

        public static string ToJson<TSource, TResult>(this TSource entity, Func<TSource, TResult> selector)
        {
            return selector(entity).ToJson();
        }

        public static XDocument ToXDocument<T>(this T obj)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            XDocument document = new XDocument();
            using (XmlWriter writer = document.CreateWriter())
            {
                serializer.Serialize(writer, obj);
            }
            return document;
        }

        public static void While<T>(this T t, Predicate<T> predicate, Action<T> action) where T: class
        {
            while (predicate(t))
            {
                action(t);
            }
        }
    }
}

